
package com.bpzj.util.messageloop;


/**
 * Defines a message containing a description and arbitrary data object that can be sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.
 *
 * <p class="note">While the constructor of Message is public, the best way to get
 * one of these is to call {@link #obtain Message.obtain()} or one of the {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull them
 * from a pool of recycled objects.</p>
 */
public final class Message {

  /**
   * User-defined message code so that the recipient can identify what this message is about. Each {@link Handler} has its own name-space for message codes, so
   * you do not need to worry about yours conflicting with other handlers.
   */
  public int what;

  /**
   * arg1 and arg2 are lower-cost alternatives to using {@link #setData(Object)} setData()} if you only need to store a few integer values.
   */
  public int arg1;

  /**
   * arg1 and arg2 are lower-cost alternatives to using {@link #setData(Object) setData()} if you only need to store a few integer values.
   */
  public int arg2;

  /**
   * An arbitrary object to send to the recipient.  When using {@link } to send the message across processes this can only be non-null if it contains a
   * Parcelable of a framework class (not one implemented by the application).   For other data transfer use {@link #setData}.
   *
   * <p>Note that Parcelable objects here are not supported prior to
   */
  public Object obj;

  /**
   * Optional Messenger where replies to this message can be sent.  The semantics of exactly how this is used are up to the sender and receiver.
   */
  public Messenger replyTo;

  /**
   * If set message is in use
   */
  /*package*/ static final int FLAG_IN_USE = 1 << 0;

  /**
   * If set message is asynchronous
   */
  /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

  /**
   * Flags to clear in the copyFrom method
   */
  /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;

  /*package*/ int flags;

  /*package*/ long when;

  // /*package*/ Bundle data;
  /*package*/ Object data;

  /*package*/ Handler target;

  /*package*/ Runnable callback;

  // sometimes we store linked lists of these things
  /*package*/ Message next;

  private static final Object sPoolSync = new Object();
  private static Message sPool;
  private static int sPoolSize = 0;

  private static final int MAX_POOL_SIZE = 50;

  /**
   * Return a new Message instance from the global pool. Allows us to avoid allocating new objects in many cases.
   */
  public static Message obtain() {
    synchronized (sPoolSync) {
      if (sPool != null) {
        Message m = sPool;
        sPool = m.next;
        m.next = null;
        sPoolSize--;
        return m;
      }
    }
    return new Message();
  }

  /**
   * Same as {@link #obtain()}, but copies the values of an existing message (including its target) into the new one.
   *
   * @param orig Original message to copy.
   * @return A Message object from the global pool.
   */
  public static Message obtain(Message orig) {
    Message m = obtain();
    m.what = orig.what;
    m.arg1 = orig.arg1;
    m.arg2 = orig.arg2;
    m.obj = orig.obj;
    m.replyTo = orig.replyTo;
    if (orig.data != null) {
      m.data = orig.data;
    }
    m.target = orig.target;
    m.callback = orig.callback;

    return m;
  }

  /**
   * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
   *
   * @param h Handler to assign to the returned Message object's <em>target</em> member.
   * @return A Message object from the global pool.
   */
  public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
  }

  /**
   * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on the Message that is returned.
   *
   * @param h        Handler to assign to the returned Message object's <em>target</em> member.
   * @param callback Runnable that will execute when the message is handled.
   * @return A Message object from the global pool.
   */
  public static Message obtain(Handler h, Runnable callback) {
    Message m = obtain();
    m.target = h;
    m.callback = callback;

    return m;
  }

  /**
   * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
   * <em>what</em> members on the Message.
   *
   * @param h    Value to assign to the <em>target</em> member.
   * @param what Value to assign to the <em>what</em> member.
   * @return A Message object from the global pool.
   */
  public static Message obtain(Handler h, int what) {
    Message m = obtain();
    m.target = h;
    m.what = what;

    return m;
  }

  /**
   * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em> members.
   *
   * @param h    The <em>target</em> value to set.
   * @param what The <em>what</em> value to set.
   * @param obj  The <em>object</em> method to set.
   * @return A Message object from the global pool.
   */
  public static Message obtain(Handler h, int what, Object obj) {
    Message m = obtain();
    m.target = h;
    m.what = what;
    m.obj = obj;

    return m;
  }

  /**
   * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
   * <em>arg1</em>, and <em>arg2</em> members.
   *
   * @param h    The <em>target</em> value to set.
   * @param what The <em>what</em> value to set.
   * @param arg1 The <em>arg1</em> value to set.
   * @param arg2 The <em>arg2</em> value to set.
   * @return A Message object from the global pool.
   */
  public static Message obtain(Handler h, int what, int arg1, int arg2) {
    Message m = obtain();
    m.target = h;
    m.what = what;
    m.arg1 = arg1;
    m.arg2 = arg2;

    return m;
  }

  /**
   * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
   * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
   *
   * @param h    The <em>target</em> value to set.
   * @param what The <em>what</em> value to set.
   * @param arg1 The <em>arg1</em> value to set.
   * @param arg2 The <em>arg2</em> value to set.
   * @param obj  The <em>obj</em> value to set.
   * @return A Message object from the global pool.
   */
  public static Message obtain(Handler h, int what,
      int arg1, int arg2, Object obj) {
    Message m = obtain();
    m.target = h;
    m.what = what;
    m.arg1 = arg1;
    m.arg2 = arg2;
    m.obj = obj;

    return m;
  }

  /**
   * Return a Message instance to the global pool.  You MUST NOT touch the Message after calling this function -- it has effectively been freed.
   */
  public void recycle() {
    clearForRecycle();

    synchronized (sPoolSync) {
      if (sPoolSize < MAX_POOL_SIZE) {
        next = sPool;
        sPool = this;
        sPoolSize++;
      }
    }
  }

  /**
   * Make this message like o.  Performs a shallow copy of the data field. Does not copy the linked list fields, nor the timestamp or target/callback of the
   * original message.
   */
  public void copyFrom(Message o) {
    this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
    this.what = o.what;
    this.arg1 = o.arg1;
    this.arg2 = o.arg2;
    this.obj = o.obj;
    this.replyTo = o.replyTo;

    if (o.data != null) {
      //
      System.out.println("这里需要改代码");
      // this.data = o.data.clone();
    } else {
      this.data = null;
    }
  }

  /**
   * Return the targeted delivery time of this message, in milliseconds.
   */
  public long getWhen() {
    return when;
  }

  public void setTarget(Handler target) {
    this.target = target;
  }

  /**
   * Retrieve the a {@link Handler Handler} implementation that will receive this message. The object must implement {@link Handler#handleMessage(Message)
   * Handler.handleMessage()}. Each Handler has its own name-space for message codes, so you do not need to worry about yours conflicting with other handlers.
   */
  public Handler getTarget() {
    return target;
  }

  /**
   * Retrieve callback object that will execute when this message is handled. This object must implement Runnable. This is called by the <em>target</em> {@link
   * Handler} that is receiving this Message to dispatch it.  If not set, the message will be dispatched to the receiving Handler's {@link
   * Handler#handleMessage(Message Handler.handleMessage())}.
   */
  public Runnable getCallback() {
    return callback;
  }

  /**
   * Obtains a Bundle of arbitrary data associated with this event, lazily creating it if necessary. Set this value by calling {@link #setData(Object)}.  Note
   * that when transferring data across processes via {@link }, you will need to set your ClassLoader on the Bundle via {@link } so that it can instantiate your
   * objects when you retrieve them.
   *
   * @see #peekData()
   * @see #setData(Object)
   */
  public Object getData() {
    if (data == null) {
      data = new Object();
    }

    return data;
  }

  /**
   * Like getData(), but does not lazily create the Bundle.  A null is returned if the Bundle does not already exist.  See {@link #getData} for further
   * information on this.
   *
   * @see #getData()
   * @see #setData(Object)
   */
  public Object peekData() {
    return data;
  }

  /**
   * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members as a lower cost way to send a few simple integer values, if you can.
   *
   * @see #getData()
   * @see #peekData()
   */
  public void setData(Object data) {
    this.data = data;
  }

  /**
   * Sends this Message to the Handler specified by {@link #getTarget}. Throws a null pointer exception if this field has not been set.
   */
  public void sendToTarget() {
    target.sendMessage(this);
  }

  /**
   * Returns true if the message is asynchronous.
   * <p>
   * Asynchronous messages represent interrupts or events that do not require global ordering with represent to synchronous messages.  Asynchronous messages are
   * not subject to the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
   *
   * @return True if the message is asynchronous.
   * @hide
   * @see #setAsynchronous(boolean)
   * @see MessageQueue#enqueueSyncBarrier(long)
   * @see MessageQueue#removeSyncBarrier(int)
   */
  public boolean isAsynchronous() {
    return (flags & FLAG_ASYNCHRONOUS) != 0;
  }

  /**
   * Sets whether the message is asynchronous.
   * <p>
   * Asynchronous messages represent interrupts or events that do not require global ordering with represent to synchronous messages.  Asynchronous messages are
   * not subject to the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
   *
   * @param async True if the message is asynchronous.
   * @hide
   * @see #isAsynchronous()
   * @see MessageQueue#enqueueSyncBarrier(long)
   * @see MessageQueue#removeSyncBarrier(int)
   */
  public void setAsynchronous(boolean async) {
    if (async) {
      flags |= FLAG_ASYNCHRONOUS;
    } else {
      flags &= ~FLAG_ASYNCHRONOUS;
    }
  }

  /*package*/ void clearForRecycle() {
    flags = 0;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    when = 0;
    target = null;
    callback = null;
    data = null;
  }

  /*package*/ boolean isInUse() {
    return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
  }

  /*package*/ void markInUse() {
    flags |= FLAG_IN_USE;
  }

  /**
   * Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
   */
  public Message() {
  }

  public String toString() {
    return toString(System.currentTimeMillis());
  }

  String toString(long now) {
    StringBuilder b = new StringBuilder();

    b.append("{ what=");
    b.append(what);

    b.append(" when=");
    // TimeUtils.formatDuration(when - now, b);

    if (arg1 != 0) {
      b.append(" arg1=");
      b.append(arg1);
    }

    if (arg2 != 0) {
      b.append(" arg2=");
      b.append(arg2);
    }

    if (obj != null) {
      b.append(" obj=");
      b.append(obj);
    }

    b.append(" }");

    return b.toString();
  }

  // public static final Parcelable.Creator<Message> CREATOR
  //         = new Parcelable.Creator<Message>() {
  //     public Message createFromParcel(Parcel source) {
  //         Message msg = Message.obtain();
  //         msg.readFromParcel(source);
  //         return msg;
  //     }
  //
  //     public Message[] newArray(int size) {
  //         return new Message[size];
  //     }
  // };

  public int describeContents() {
    return 0;
  }

  // public void writeToParcel(Parcel dest, int flags) {
  //     if (callback != null) {
  //         throw new RuntimeException(
  //                 "Can't marshal callbacks across processes.");
  //     }
  //     dest.writeInt(what);
  //     dest.writeInt(arg1);
  //     dest.writeInt(arg2);
  //     if (obj != null) {
  //         try {
  //             Parcelable p = (Parcelable) obj;
  //             dest.writeInt(1);
  //             dest.writeParcelable(p, flags);
  //         } catch (ClassCastException e) {
  //             throw new RuntimeException(
  //                     "Can't marshal non-Parcelable objects across processes.");
  //         }
  //     } else {
  //         dest.writeInt(0);
  //     }
  //     dest.writeLong(when);
  //     dest.writeBundle(data);
  //     Messenger.writeMessengerOrNullToParcel(replyTo, dest);
  // }

  // private void readFromParcel(Parcel source) {
  //     what = source.readInt();
  //     arg1 = source.readInt();
  //     arg2 = source.readInt();
  //     if (source.readInt() != 0) {
  //         obj = source.readParcelable(getClass().getClassLoader());
  //     }
  //     when = source.readLong();
  //     data = source.readBundle();
  //     replyTo = Messenger.readMessengerOrNullFromParcel(source);
  // }
}
